#pragma once

#include <deque>
#include <string>

namespace Mesh
{
	/**
	 * @file Mesh.h
	 * @author xingyifan
	 * @date 2022-12-15 13:22
	 *
	 * @description: 三维点/向量
	 */

	class vector3f
	{
	public:
		double x, y, z;

	public:
		vector3f(double x = 0, double y = 0, double z = 0) : x(x), y(y), z(z) {}

		// 基本运算
		vector3f operator*(double t) const;
		vector3f operator/(double t) const;
		vector3f operator-(const vector3f &v) const;
		vector3f operator+(const vector3f &v) const;
		friend vector3f operator-(const vector3f &v);
	};

	class point3f
	{
	public:
		double x, y, z;

	public:
		point3f(double x = 0, double y = 0, double z = 0) : x(x), y(y), z(z) {}

		vector3f operator-(const point3f &p) const;					   // 顶点相减得到向量
		friend point3f operator+(const point3f &p, const vector3f &v); // 顶点 + 向量 = 顶点
		friend point3f operator+(const vector3f &v, const point3f &p); // 向量 + 顶点 = 顶点
	};

	/**
	 * @file Mesh.h
	 * @author xingyifan
	 * @date 2022-12-26 16:16
	 *
	 * @description: 四元数
	 */

	class quaternion
	{
	public:
		double s;
		vector3f v;

	public:
		// 常规初始化，分量初始化、默认初始化，纯四元数初始化
		quaternion(double a, double b, double c, double d) : s(a), v({b, c, d}) {}
		quaternion(double s = 0, vector3f v = {0, 0, 0}) : s(s), v(v) {}
		quaternion(vector3f v) : s(0), v(v) {}

		// 获得绕轴 v 旋转 theta 角的四元数
		quaternion(vector3f v, double theta);

		// 四元数基本运算
		quaternion operator*(double t) const;
		quaternion operator/(double t) const;
		quaternion operator+(const quaternion &q) const;
		quaternion operator-(const quaternion &q) const;
		quaternion operator*(const quaternion &q) const;
		quaternion operator/(const quaternion &q) const;
	};

	/**
	 * @file Mesh.h
	 * @author xingyifan
	 * @date 2022-12-15 13:22
	 *
	 * @description: 4 维齐次坐标
	 */

	class coord4f
	{
	public:
		double x, y, z;
		int w;

	public:
		coord4f(double x = 0, double y = 0, double z = 0, int w = 0) : x(x), y(y), z(z), w(w) {}
		coord4f(const point3f &p) : x(p.x), y(p.y), z(p.z), w(1) {}
		coord4f(const vector3f &p) : x(p.x), y(p.y), z(p.z), w(0) {}

		// 隐式转换
		operator point3f() const { return {x, y, z}; }
		operator vector3f() const { return {x, y, z}; }

		// 基本运算
		coord4f operator*(double t) const;
		coord4f operator/(double t) const;
		coord4f operator-(const coord4f &v) const;
		coord4f operator+(const coord4f &v) const;
		friend coord4f operator-(const coord4f &v);
	};

	// 颜色结构
	class rgb_space
	{
	public:
		double r, g, b;

	public:
		rgb_space(double r = 0, double g = 0, double b = 0) : r(r), g(g), b(b) {}
		rgb_space operator+(const rgb_space &c1) const; // 颜色直接叠加
	};

	struct vertex3f;
	struct half_edge;
	struct face;

	// 3 维顶点
	struct vertex3f
	{
		/**
		 * @file Mesh.h
		 * @author xingyifan
		 * @date 2022-11-25 20:57
		 *
		 * @description: 基础信息
		 */

		point3f pos;  // 坐标
		half_edge *e; // 以它为起点的一条半边

		/**
		 * @file Mesh.h
		 * @author xingyifan
		 * @date 2022-11-25 20:58
		 *
		 * @description: 附加信息
		 */

		int identity; // 顶点 id 标记
	};

	// 面片
	struct face
	{
		/**
		 * @file Mesh.h
		 * @author xingyifan
		 * @date 2022-11-25 20:58
		 *
		 * @description: 基础信息
		 */

		half_edge *e; // 面边界上的一条半边

		/**
		 * @file Mesh.h
		 * @author xingyifan
		 * @date 2022-11-25 20:58
		 *
		 * @description: 附加信息
		 */

		int identity; // 面标记
	};

	// 半边结构
	struct half_edge
	{
		/**
		 * @file Mesh.h
		 * @author xingyifan
		 * @date 2022-12-17 22:25
		 *
		 * @description: 基础信息
		 */

		vertex3f *v;	 // 起点
		half_edge *twin; // 反向边，不一定存在
		face *incFace;	 // 沿着半边方向左边的面，这个面一定存在
		half_edge *prev; // 上一条半边，一定存在，在面上
		half_edge *next; // 下一条半边，一定存在，在面上

		/**
		 * @file Mesh.h
		 * @author xingyifan
		 * @date 2022-12-17 22:25
		 *
		 * @description: 附加信息
		 */

		int identity; // 半边标记
	};

	/**
	 * @file Mesh.h
	 * @author xingyifan
	 * @date 2022-12-04 11:38
	 *
	 * @description: 基于半边结构的网格
	 */

	class HEMesh
	{
	public:
		~HEMesh();

		/**
		 * @file Mesh.h
		 * @author xingyifan
		 * @date 2022-11-25 13:16
		 *
		 * @description: 初始化操作
		 */

		vertex3f *CreateVertex(point3f p);										  // 创建顶点，并返回指针
		face *CreateFace(vertex3f *v0, vertex3f *v1, vertex3f *v2);				  // 创建三角面并返回，自动判定衔接相邻面
		face *CreateFace(vertex3f *v0, vertex3f *v1, vertex3f *v2, vertex3f *v3); // 创建两个三角面并返回，自动判定衔接相邻面

		/**
		 * @file Mesh.h
		 * @author xingyifan
		 * @date 2022-11-25 20:34
		 *
		 * @description: 获取基本网格信息
		 */

		size_t VertexNum() const { return m_vList.size(); }
		size_t FaceNum() const { return m_fList.size(); }

		/**
		 * @file Mesh.h
		 * @author xingyifan
		 * @date 2022-11-25 13:16
		 *
		 * @description: 结构删除操作
		 */

		void DeleteVertex(vertex3f *v); // 删除顶点和相邻的面及其半边
		void DeleteFace(face *f);		// 删除面和对应的半边
		void DeleteDiscrete();			// 清除孤立点，返回清除的点个数

		/**
		 * @file Mesh.h
		 * @author xingyifan
		 * @date 2022-12-15 14:07
		 *
		 * @description: 附加判断
		 */

		bool HasVertexNormal() const;	// 是否有顶点法向
		bool HasVertexColor() const;	// 是否有顶点颜色
		bool IsConvexHull() const;		// 判断网格是否是凸包
		bool IsInMesh(point3f p) const; // 判断点是否在网格包围中

	public:
		/**
		 * @file Mesh.h
		 * @author xingyifan
		 * @date 2022-12-15 13:55
		 *
		 * @description: 基本数据结构
		 */

		std::deque<vertex3f *> m_vList;	 // 顶点列表
		std::deque<half_edge *> m_eList; // 半边列表
		std::deque<face *> m_fList;		 // 面列表

		/**
		 * @file Mesh.h
		 * @author xingyifan
		 * @date 2022-12-15 13:55
		 *
		 * @description: 附加信息
		 */

		std::deque<rgb_space> m_cList; // 颜色列表
		std::deque<vector3f> m_nList;  // 法向列表
	};

	/**
	 * @file Mesh.h
	 * @author xingyifan
	 * @date 2022-12-03 14:58
	 *
	 * @description: 一般结构操作
	 */

	rgb_space linear(rgb_space c1, rgb_space c2, double t);						  // 颜色线性插值
	point3f linear(point3f p1, point3f p2, double t, double a = 0, double b = 1); // 点线性插值
	double distance(point3f p1, point3f p2);									  // 计算点的距离
	double det(vector3f v1, vector3f v2, vector3f v3);							  // 行列式 (v1 x v2) * v3
	double dot(vector3f v1, vector3f v2);										  // 向量点积
	vector3f cross(vector3f v1, vector3f v2);									  // 向量叉积
	vector3f normalize(vector3f p);												  // 向量规范化
	quaternion normalize(quaternion q);											  // 四元数规范化
	double length(vector3f p);													  // 向量长度
	double length(quaternion q);												  // 四元数长度
	bool onLine(point3f p1, point3f p2, point3f p3);							  // 判断三点是否共线
	quaternion rotate(vector3f a, vector3f b);									  // 获得从轴 a 转动到轴 b 的四元数

	/**
	 * @file Mesh.h
	 * @author xingyifan
	 * @date 2022-12-15 13:27
	 *
	 * @description: 网格方法
	 */

	bool stitchFace(face *f1, face *f2);					  // “缝合”两个面，返回是否成功
	bool onFace(point3f p, face *f);						  // 判断一个点是否在面上
	bool aboveFace(point3f p, face *f);						  // 判断一个点是否在面的上方
	vector3f Gouraud(vertex3f *v);							  // Gouraud 插值：计算顶点的平均法向
	vector3f faceNormal(face *f);							  // 计算单位面法向
	vertex3f *destination(half_edge *e);					  // 获得边的目标点
	std::deque<vertex3f *> vertexOnFace(face *f);			  // 获得一个面上的所有顶点
	std::deque<half_edge *> halfEdgeOnFace(face *f);		  // 获得一个面上的所有半边
	std::deque<half_edge *> commonOnFace(face *f0, face *f1); // 获取两个面的公共半边
	std::deque<vertex3f *> adjacentVertex(vertex3f *v);		  // 获得 v 相邻的所有顶点
	std::deque<half_edge *> adjacentHalfEdge(vertex3f *v);	  // 获得以 v 为起点的半边
	std::deque<face *> adjacentFace(vertex3f *v);			  // 获得 v 相邻的所有面
	std::deque<face *> adjacentFace(face *f);				  // 获得 f 相邻的所有面

	/**
	 * @file Mesh.h
	 * @author xingyifan
	 * @date 2022-12-17 22:19
	 *
	 * @description: 凸包算法
	 */

	bool tetrahedron(HEMesh *mesh); // 尝试用网格点创建四面体，返回是否成功
	bool convexHull(HEMesh *mesh);	// 取网格点的凸包，返回是否成功
	bool fixMesh(HEMesh *mesh);		// 修复网格，有时删除操作造成某些非离散点存放的半边为空，此函数修复这一问题，返回是否进行了修复

	/**
	 * @file Mesh.h
	 * @author xingyifan
	 * @date 2022-12-26 11:41
	 *
	 * @description: 常见曲面生成
	 */

	bool sphere(HEMesh *mesh, point3f center, double a, double b, double c, int div = 20);						  // 球面：中心位置、三个半长轴，分割份数
	bool cylinder(HEMesh *mesh, point3f center, vector3f axis, double r, double h, int divr = 40, int divh = 40); // 柱面：中心位置，中轴，半径，高度，分割份数

	/**
	 * @file Mesh.h
	 * @author xingyifan
	 * @date 2022-12-25 19:33
	 *
	 * @description: 保存和读取操作
	 */

	bool saveMesh(const std::string &filename, HEMesh *mesh);
	bool loadMesh(const std::string &filename, HEMesh *mesh);
};
